#!/usr/bin/env python
# -*- coding: UTF-8 -*-
'''
@Project ：MicInter_IPCamera 
@File    ：voice.py
@IDE     ：PyCharm 
@Author  ：董文捷
@Date    ：2025/11/5 19:49 
'''
import pyaudio
import json
import time
import subprocess
import pyttsx3
from vosk import Model, KaldiRecognizer
import sys
import os
import re
import comtypes.client
import shutil
import os

# 添加当前目录到Python路径
sys.path.append(os.path.dirname(os.path.abspath(__file__)))

# === 初始化语音合成 ===
engine = pyttsx3.init()
engine.setProperty('rate', 160)
engine.setProperty('volume', 1.0)


def speak(text):
    print("🗣️ 回应：" + text)
    engine.say(text)
    engine.runAndWait()


# === 初始化 VOSK 模型 ===
try:
    model_path = "vosk-model-small-cn-0.22"
    if not os.path.exists(model_path):
        raise FileNotFoundError(f"找不到VOSK模型: {model_path}")

    model = Model(model_path)
    recognizer = KaldiRecognizer(model, 16000)
    print("✅ VOSK模型加载成功")
except Exception as e:
    print(f"❌ VOSK模型加载失败: {e}")
    sys.exit(1)

# === 状态控制 ===
stop_flag = False
task_running = False
wakeup_mode = False
wakeup_time = 0
WAKEUP_TIMEOUT = 10  # 唤醒后等待指令的时间（秒）

# 程序映射表
program_mapping = {
    "30": "program_30",
    "40": "program_40",
    "50": "program_50"
}

# 扩展中文数字到阿拉伯数字的映射
chinese_number_map = {
    "零": "0", "一": "1", "二": "2", "三": "3", "四": "4",
    "五": "5", "六": "6", "七": "7", "八": "8", "九": "9",
    "十": "10", "二十": "20", "三十": "30", "四十": "40", "五十": "50",
    "幺": "1", "两": "2", "叁": "3", "肆": "4", "伍": "5",
    "陆": "6", "柒": "7", "捌": "8", "玖": "9", "拾": "10",
    # 添加更多可能的语音识别结果
    "运行三十": "30", "运行四十": "40", "运行五十": "50",
    "启动三十": "30", "启动四十": "40", "启动五十": "50",
    "执行三十": "30", "执行四十": "40", "执行五十": "50",
    "我的运行三十": "30", "我的运行四十": "40", "我的运行五十": "50",
    "我要运行三十": "30", "我要运行四十": "40", "我要运行五十": "50",
    "请运行三十": "30", "请运行四十": "40", "请运行五十": "50"
}

# === 初始化音频流 ===
try:
    p = pyaudio.PyAudio()
    stream = p.open(
        format=pyaudio.paInt16,
        channels=1,
        rate=16000,
        input=True,
        frames_per_buffer=4000
    )
    stream.start_stream()
    print("✅ 音频流初始化成功")
except Exception as e:
    print(f"❌ 音频流初始化失败: {e}")
    sys.exit(1)


def convert_chinese_to_digit(text):
    """
    将中文数字转换为阿拉伯数字
    例如: "我的运行三十" -> "30", "运行四十" -> "40"
    """
    print(f"🔍 转换函数输入: '{text}'")

    # 首先去除所有空格
    clean_text = text.replace(" ", "")
    print(f"🔍 去除空格后: '{clean_text}'")

    # 定义常见无关词语，这些词语应该被忽略
    irrelevant_words = ["我的", "我要", "我想", "请", "帮忙", "运行", "启动", "执行", "的"]

    # 移除无关词语
    for word in irrelevant_words:
        clean_text = clean_text.replace(word, "")
    print(f"🔍 移除无关词语后: '{clean_text}'")

    # 尝试直接匹配完整的中文数字（按照长度从长到短排序，优先匹配更长的）
    sorted_keys = sorted(chinese_number_map.keys(), key=len, reverse=True)
    for chinese in sorted_keys:
        if chinese in clean_text:
            digit = chinese_number_map[chinese]
            print(f"🔍 直接匹配: '{chinese}' -> '{digit}'")
            return digit

    # 如果没有直接匹配，尝试提取数字部分
    # 使用正则表达式提取可能的中文数字
    chinese_digits = re.findall(r'[零一二三四五六七八九十百千万亿]+', clean_text)
    print(f"🔍 正则匹配结果: {chinese_digits}")

    if chinese_digits:
        # 取最长匹配的中文数字
        chinese_num = max(chinese_digits, key=len)
        print(f"🔍 提取中文数字: '{chinese_num}'")

        # 处理常见数字
        if chinese_num in chinese_number_map:
            return chinese_number_map[chinese_num]

        # 处理"四十"、"三十"等特殊情况
        if chinese_num == "四十":
            return "40"
        elif chinese_num == "三十":
            return "30"
        elif chinese_num == "五十":
            return "50"

    # 如果没有找到中文数字，尝试提取阿拉伯数字
    arabic_digits = re.findall(r'\d+', clean_text)
    print(f"🔍 提取阿拉伯数字: {arabic_digits}")

    if arabic_digits:
        return arabic_digits[0]

    print("🔍 未找到匹配的数字")
    return None


# === 执行指定程序 ===
def start_program(program_name):
    global task_running
    if task_running:
        print("⚠️ 任务正在进行中，忽略重复指令")
        return

    task_running = True
    print(f"✅ 开始执行程序: {program_name}")
    speak(f"开始执行{program_name}程序")

    try:
        # 检查程序文件是否存在
        if not os.path.exists(f"{program_name}.py"):
            raise FileNotFoundError(f"找不到程序文件: {program_name}.py")

        # 使用subprocess运行外部Python文件
        subprocess.run(["python", f"{program_name}.py"], check=True)
        print(f"✅ 程序 {program_name} 执行完成")
        speak("任务完成")
    except subprocess.CalledProcessError as e:
        print(f"❌ 程序执行失败：{e}")
        speak("任务失败")
    except Exception as e:
        print(f"❌ 异常错误：{e}")
        speak("发生错误")

    task_running = False


# === 主循环 ===
print("🎤 离线语音控制系统启动（VOSK）")
print("🗣️ 说 '小麦' 唤醒，然后说 '运行30'、'运行40' 或 '运行50' 执行对应程序")
print("🗣️ 或者说 '运行三十'、'运行四十'、'运行五十'")

try:
    while not stop_flag:
        data = stream.read(4000, exception_on_overflow=False)

        if recognizer.AcceptWaveform(data):
            result = json.loads(recognizer.Result())
            text = result.get("text", "").strip()
            if not text:
                continue

            print(f"📝 指令识别：{text}")
            current_time = time.time()

            # 唤醒指令（模糊匹配"小麦"）
            if "小麦" in text or "小差" in text or "小卖" in text:  # 添加常见误识别
                wakeup_mode = True
                wakeup_time = current_time
                speak("我在")
                continue

            # 如果处于唤醒状态且未超时
            if wakeup_mode:
                if current_time - wakeup_time > WAKEUP_TIMEOUT:
                    print("⏳ 唤醒超时，退出唤醒状态")
                    wakeup_mode = False
                    continue

                # 运行程序指令
                if "运行" in text or any(num in text for num in ["三十", "四十", "五十", "30", "40", "50"]):
                    # 提取并转换数字部分
                    print(f"🔍 原始识别文本: '{text}'")
                    digit = convert_chinese_to_digit(text)
                    print(f"🔍 最终转换结果: '{text}' -> '{digit}'")

                    if digit and digit in program_mapping:
                        program_name = program_mapping[digit]
                        print(f"🟢 触发运行程序: {program_name} (识别数字: {digit})")
                        start_program(program_name)
                        wakeup_mode = False
                    else:
                        speak(f"找不到对应的程序，请重试")
                        print(f"❌ 无法识别数字或找不到程序: {text}")
                        # 提供帮助信息
                        print("💡 请尝试说: '运行30', '运行40', '运行50', '运行三十', '运行四十' 或 '运行五十'")

                elif "停止" in text or "退出" in text or "结束" in text:
                    print("🛑 收到停止指令")
                    speak("好的，我退出")
                    stop_flag = True

except KeyboardInterrupt:
    print("\n🛑 手动中断程序")
    speak("已终止")
except Exception as e:
    print(f"❌ 发生错误: {e}")
    speak("程序出错")

# === 清理资源 ===
stream.stop_stream()
stream.close()
p.terminate()
print("👋 程序已退出")
